package ru.dcsearch.indexer;

/***************************************************************************
 *   Modified by TMC
 *   berechitai@gmail.com
 *
 *   This file is part of DC Indexer project
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 ***************************************************************************/
/*
 *  Mobile DC - a DirectConnect client written in Java and designed for
 *  the Sony Ericsson p800/p900 or equivalent Symbian OS 7.0 platforms
 *  Copyright (C) 2004 Conrad Helgesson, vakum@home.se
 *
 *  This file is part of Mobile DC.
 *
 *  Mobile DC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  Mobile DC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Mobile DC; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

import java.io.OutputStream;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.util.Hashtable;

// handles input from the server, own thread
public class NetWorker extends Thread
{
	private boolean toStop = false;
	
	private DCClient mw;
	private String hubcount = "1/0/0"; // Hubcount in MyINFO string in "x/x/x form
	private String hubname = "";
	private DCEncryptionHandler encryptionHandler = new DCEncryptionHandler();
	private OutputStream out;

	//SearchSpy
	private boolean	processSearch = false;

	public Hashtable net_ucmds = new Hashtable();
	//public Tree2 net_ucmds_tree = new Tree2(200, 300); //Should be enough :P
	public boolean NoGetINFO = false;
	public boolean NoHello = false;
	public boolean loggingin = false;

    final static char COMMAND_END_CHAR = '|';
	final static char COMMAND_SEP_CHAR = ' ';
	final static char COMMAND_BEG_CHAR = '$';


	public NetWorker(DCClient w)
	{
		mw = w;
		try {
			if(mw.nh.isConnected) out = mw.nh.s.getOutputStream();
		} catch(Exception e) {
			mw.nh.disconnect("");
		}
	}

	// return the hubname we are connected to
	public String hubname()
	{
		return hubname;
	}

	// return the hubcountstring
	public String hubcount()
	{
		return hubcount;
	}

	// the main method for the thread
	public void run()
	{
		if (toStop) return;
		if(mw.nh.isConnected) {
			try {
				String fromServer;
				while(true) {
					if (toStop) return;
					while((fromServer = mw.nh.getIn().readToken()) == null) {
						sleep(10);
					}
					handleMsg(fromServer);
				}
			} catch(SocketException e) {
				Logger.printLog("NetWorker Disconnect: "+e);
				if(mw.nh.isConnected) mw.nh.disconnect("*** Connection reset by peer.");
			} catch(InterruptedIOException e) {
				Logger.printLog("NetWorker Disconnect: "+e);
				if(mw.nh.isConnected) mw.nh.disconnect("*** Connection timeout"); //possible?
			} catch(Exception e) {
				Logger.printLog("NetWorker Disconnect: "+e);
				if(mw.nh.isConnected) mw.nh.disconnect("");
			}
        }

	}

	private int AddDL(int i) {
		mw.DLtraffic += (i+1);
		return i;
	}

	// parse msg from server and decide what to do
	public void handleMsg(String msg)// throws IOException
	{
		String inccmd = "";
		String incdat = "";
		//Logger.printLog("IN: "+msg+COMMAND_END_CHAR);

		if(AddDL(msg.length()) == 0) return;
		//mw.timer.GotData();

		int sepindex = msg.indexOf(COMMAND_SEP_CHAR);
		if(sepindex < 0) inccmd = msg;
		else {
			inccmd = msg.substring(0, sepindex);
			incdat = msg.substring(sepindex+1, msg.length());
		}


		// process the incoming string
		if(inccmd.charAt(0) == COMMAND_BEG_CHAR){
			// handle hubmessages
			
			//QUIT message
			if("$Quit".equals(inccmd)) {
				cmdDelete(incdat);
			
			} else 
				
			//HELLO message	
			if ("$Hello".equals(inccmd)) {
				cmdHello(incdat);
                Logger.printGlobalLog("Logged in.");
			} else if ("$Search".equals(inccmd)) {
				if(!processSearch) return;
				cmdSearch(incdat);
			} else if ("$MyINFO".equals(inccmd)) {
				cmdMyINFO(incdat);
			} else if ("$UserCommand".equals(inccmd)) {
				cmdUserCommand(incdat);
			} else if ("$NickList".equals(inccmd)) {
				cmdNickList(incdat);
			} else if ("$OpList".equals(inccmd)) {
				cmdOpList(incdat);
			} else if ("$Lock".equals(inccmd)) {
				cmdLock(msg, incdat);
			} else if ("$HubName".equals(inccmd)) {
				cmdHubName(incdat);
			} else if ("$ValidateDenide".equals(inccmd)) {
				cmdValidateDenide();
			} else if("$To:".equals(inccmd)) {
				cmdTo(incdat);
			} else if ("$LogedIn".equals(inccmd)) {
				cmdLoggedIn();
			} else if ("$GetPass".equals(inccmd)) {
				cmdGetPass();
			} else if ("$BadPass".equals(inccmd)) {
				cmdBadPass();
			} else if ("$SR".equals(inccmd)) {
				//mw.sm.ManageResponse(incdat);
			} else if ("$RevConnectToMe".equals(inccmd)) {
				cmdRevConnectToMe(incdat);
			} else if ("$ConnectToMe".equals(inccmd)) {
				cmdConnectToMe();
			} else if ("$Supports".equals(inccmd)) {
				cmdSupports(incdat);
			} else if ("$ForceMove".equals(inccmd)) {
				cmdForceMove(incdat);
			} else {
				//Unknown command heading with $
			}
		
		} else if(inccmd.charAt(0) == '<') {
			// handle mainmessages
			if(incdat.startsWith("/me"))
				Logger.printLog("** "+inccmd.substring(1,inccmd.length()-1)+COMMAND_SEP_CHAR+incdat.substring(incdat.indexOf("/me ")+4));
			else
				Logger.printLog(msg);
		} else {
			//Unknown commmand heading with neither $ nor <
			//handle this as mainchatmsg if it's longer than...ehm...2 chars :)
			//if(msg.length() >= 3) addMsg(mw.windowmc, msg);
			if(msg.length() >= 3) Logger.printLog(msg);
		}

	}
/*
 * COMMAND HANDLERS
 * 
 */
	private void cmdForceMove(String incdat) {
		if(mw.p.IsEnabled("folredir")) {
			mw.nh.disconnect("*** You were Redirected.");
			String port, hub;
			try {
				hub = incdat.substring(0, incdat.indexOf(':'));
				port = incdat.substring(incdat.indexOf(':')+1);
			} catch(StringIndexOutOfBoundsException err) {
				hub = incdat;
				port = "411";
			}
			
		} else {
			Logger.printLog("*** Redirect: "+incdat);
			mw.nh.disconnect("");

		}
	}

	private void cmdSupports(String incdat) {
		int i = 0;
		int length = incdat.length()-1;
		StringBuffer buffer = new StringBuffer();
		while(true) {
			if(i == length) {
				buffer.append(incdat.charAt(i));
				if(buffer.toString().equals("NoGetINFO")) NoGetINFO = true;
				else if(buffer.toString().equals("NoHello")) NoHello = true;
				break;
			}

			if(incdat.charAt(i) == COMMAND_SEP_CHAR) {
				if(buffer.toString().equals("NoGetINFO")) NoGetINFO = true;
				else if(buffer.toString().equals("NoHello")) NoHello = true;
				buffer = new StringBuffer();
			} else
				buffer.append(incdat.charAt(i));
			i++;
		}
		buffer = null;
	}

	private void cmdConnectToMe() {
		Logger.printLog("ConnnectToMeRecieved");
		//mw.P2P.NewCC("", incdat.substring(incdat.indexOf(COMMAND_SEP_CHAR)+1, incdat.indexOf(':')), Integer.parseInt(incdat.substring(incdat.indexOf(':')+1, incdat.length())), "", mw.P2P.Unknown);
	}

	private void cmdRevConnectToMe(String incdat) {
		String user = incdat.substring(0, incdat.indexOf(COMMAND_SEP_CHAR));
		/*if(mw.p.get("mode").equals("A")) {
			sendCommand("$ConnectToMe", user+COMMAND_SEP_CHAR+mw.p.get("locip")+":"+mw.p.get("locport"));
			mw.P2P.NewCC(user, "", 0, "", mw.P2P.Upload);
		} else if(mw.P2P.RevConnectDLlist.containsKey(user)) {
			mw.setBstatus("*** Passive P2P unable to "+user);
			mw.P2P.RevConnectDLlist.remove(user);
		} else { //Like f*** you, Revconnect to me ffs omg omg :P
			sendCommand("$RevConnectToMe", mw.p.getMynick()+COMMAND_SEP_CHAR+user);
		}
		*/
	}

	private void cmdBadPass() {
		Logger.printLog("*** That password was incorrect");
		mw.nh.disconnect("");
	}

	private void cmdGetPass() {
		if(!mw.p.getMypass().equals("")) {
			sendCommand("$MyPass",mw.p.getMypass());
			Logger.printLog("*** Stored password sent...");
		}
		hubcount = "0/1/0"; // Hubcount
	}

	private void cmdLoggedIn() {
		hubcount = "0/0/1";
		sendMyINFO();
	}

	private void cmdTo(String incdat) {
		String winuser = incdat.substring(incdat.indexOf("From: ")+6, incdat.indexOf(COMMAND_BEG_CHAR)-1);
		String winmsg = incdat.substring(incdat.indexOf(COMMAND_BEG_CHAR)+1,incdat.length());
		// confirm that it is a valid private message
		/*if(winuser.length() > 0 && winmsg.length() > 0) {
			if(!mw.WinPanelExists(winuser)) {
				mw.NewWinPanel(winuser);
				if(mw.p.IsEnabled("popupmsg")) mw.setActive(winuser); // popup the new msg.
				else mw.setBstatus("*** New message from "+winuser);
			} else if(mw.active.compareTo(winuser) != 0)
				mw.setBstatus("*** New message from "+winuser); // PM window is in the background, notification in bstatus
			mw.Println(winuser, winmsg);
			if(mw.p.IsEnabled("beep_pm")) java.awt.Toolkit.getDefaultToolkit().beep();
		}*/
	}

	private void cmdValidateDenide() {
		mw.nh.disconnect("*** Nickname already taken");
	}

	private void cmdHubName(String incdat) {
		hubname = incdat;
	}

	private void cmdLock(String msg, String incdat) {
		String thelock=incdat.substring(0,msg.indexOf(" Pk=")-6);
		Logger.printLog(incdat.substring(0,msg.indexOf(" Pk=")-6));
		//mw.addToStatus("*** Connected");
		String thekey = encryptionHandler.calculateValidationKey(thelock);
		if(thelock.startsWith("EXTENDEDPROTOCOL")) {
			String list = "";
			if(mw.p.usrcmds) list += "UserCommand ";
			if(mw.p.ulstmyinfo) list += "NoGetINFO NoHello";
			sendCommand("$Supports",list);
			list = null;
			}
		sendCommand("$Key",thekey);
		loggingin = true;
		sendCommand("$ValidateNick",mw.p.getMynick());
		hubcount = "1/0/0"; // Hubcount
	}

	private void cmdOpList(String incdat) {
		// recieved a list of operators connected to the hub
        for (String curUser: incdat.split("$$")){
            mw.ul.AddOP(curUser);
        }
	}

	private void cmdNickList(String incdat) {
		// recieved a list of users connected to the hub
		Logger.printLog("*** Received Userlist...");
		mw.ul.ProcessNicklist(incdat);
		Logger.printLog("*** Userlist Processed.");
	}

	private void cmdUserCommand(String incdat) {
		if(!mw.p.usrcmds)
			return;
		int i1 = incdat.indexOf(COMMAND_SEP_CHAR);
		/*if(i1 == -1) return;
		int i2 = incdat.indexOf(COMMAND_SEP_CHAR, i1+1);
		if(i2 == -1) i2 = incdat.length();
		if(i2 <= i1) return;

		if(Integer.parseInt(incdat.substring(0, i1)) == 255 && Integer.parseInt(incdat.substring(i1+1, i2)) > 6) {
			net_ucmds_tree = new Tree2(200, 300); //Erase everything previously sent and reset.
			return;
		}
		if(Integer.parseInt(incdat.substring(0, i1)) == 0) {
			net_ucmds_tree.addSubItem("-"); //Add Separator
			net_ucmds_tree.addCD();
			net_ucmds.put("-", "");
			return;
		}
		int i3 = incdat.indexOf(COMMAND_BEG_CHAR);
		if(i3 == -1) return;
		String name = incdat.substring(i2+1,i3);
		int i4 = incdat.length();
		if(!(i4-6 < i3+1)) {
			String raw = incdat.substring(i3+1,i4-6);
			net_ucmds.put(name, raw);
		}
		//add name to tree
		net_ucmds_tree.add(name);
*/
	}

	private void cmdMyINFO(String incdat) {
		if(((NoHello && mw.p.ulstmyinfo) || mw.p.ulstmyinfo) && mw.ul.hasNicklist)
			mw.ul.PutINFO(incdat);
	}

	private void cmdSearch(String incdat) {
		/*SearchCount += 1;
		int start = incdat.indexOf('?');
		start = incdat.indexOf('?', start+1);
		start = incdat.indexOf('?', start+1);
		start = incdat.indexOf('?', start+1)+1;
		if(start == 0) return;
		incdat = incdat.replace(COMMAND_BEG_CHAR, COMMAND_SEP_CHAR);
		mw.sspylist.add(incdat.substring(start));
		if(mw.active.compareTo(mw.windowsspy) == 0) {
			double s = (System.currentTimeMillis() - processStart) / 1000.0;
			DecimalFormat fmt = new DecimalFormat("##.##");
			mw.label_filelist.setText("  Average/s: "+fmt.format((double)(SearchCount/s)));
		}*/
	}

	private void cmdHello(String incdat) {
		//if it is really our nick
		if(incdat.equals(mw.p.getMynick())) {
			
			if(loggingin) {
				sendCommand("$Version","1,0091");
				sendMyINFO();
				if(mw.p.IsEnabled("ulstlogin")) {
					sendCommand("$GetNickList");
					if(NoHello && NoGetINFO) mw.ul.hasNicklist = true;
				} else {
					mw.ul.hasNicklist = true;
					
				}
				loggingin = false;
			} else
		    	sendMyINFO();
			
		} else if(mw.p.ulstmyinfo && mw.ul.hasNicklist && !NoGetINFO)
			sendCommand("$GetINFO",incdat+COMMAND_SEP_CHAR+mw.p.getMynick());
		// Notify in PMwindow if such exists:
		
		mw.ul.AddUser(incdat);
	}

	private void cmdDelete(String incdat) {
		mw.ul.DelUser(incdat);
		// Notify in PMwindow if such exists:
	}
	
	/*
	 * 
	 * END OF COMMAND HANDLERS
	 * 
	 */

	// Send MyINFO
	public void sendMyINFO() {
    	if(!mw.OLDTAG) sendCommand("$MyINFO","$ALL "+mw.p.getMynick()+" "+mw.p.getDesc()+"<StrgDC++ V:2.03,M:A,H:1/0/0,S:2>$ $100."+(byte)1+COMMAND_BEG_CHAR+"test@test.com"+COMMAND_BEG_CHAR+"5782357723"+COMMAND_BEG_CHAR);
    	else sendCommand("$MyINFO","$ALL "+mw.p.getMynick()+COMMAND_SEP_CHAR+mw.p.getDesc()+"<StrgDC++ V:2.03,M:A,H:1/0/0,S:2>$ $100."+(byte)1+(byte)1+COMMAND_BEG_CHAR+"test@test.com"+COMMAND_BEG_CHAR+"5782357723"+COMMAND_BEG_CHAR);
	}

	// Send Private Message to someone
	public void sendPrivateMessage(String message, String nick) {
		sendCommand("$To:", nick+" From: "+mw.p.getMynick()+" $<"+mw.p.getMynick()+"> "+message);
	}

	// Sends various strings to hub
	public void sendCommand(String command, String data) {
		if(mw.nh.isConnected) {
			AddUL(command.length()+data.length()+1);
			try {
				out.write((command+COMMAND_SEP_CHAR+data+COMMAND_END_CHAR).getBytes("ISO-8859-1"));
				Logger.printLog("OUT: "+command+COMMAND_SEP_CHAR+data+COMMAND_END_CHAR);
				out.flush();
			} catch(Exception e) {
				mw.nh.disconnect("");
			}
		}
	}

	// Sends various strings to hub
	public void sendCommand(String command) {
		if(mw.nh.isConnected) {
			AddUL(command.length());
			try {
				out.write((command+COMMAND_END_CHAR).getBytes("ISO-8859-1"));
				Logger.printLog("OUT: "+command+COMMAND_END_CHAR);
				out.flush();
			} catch(Exception e) {
				mw.nh.disconnect("");
			}
		}
	}

	private void AddUL(int i) {
		mw.ULtraffic += (i+1);
	}

	/*public void MonitorSearch(boolean work)
	{
		processSearch = work;
		processStart = System.currentTimeMillis();
		SearchCount = 0;
	}
	*/
	public void stopThread() {
		
		toStop = true;
		
	}

}